#if defined(WIN32)
	// Visual C++ Memory leak detector headers
	#define _CRTDBG_MAP_ALLOC
	#include <stdlib.h>
	#include <crtdbg.h>
#endif

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>

#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>

#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <boost/shared_ptr.hpp>

#include "tinyxml.h"
#include <scott/SType.h>
#include <scott/DescriptorsRepository.h>
#include <scott/SEnumTypeDescriptor.h>

#include <scott/Plugin.h>
#include <scott/LastLoadedFirstNameResolutor.h>

using namespace std;
using namespace boost;

string GetAttribute( TiXmlElement* elem, string attributeName );
void ParsePluginDescriptors();
void GenerateEntrypoint();
void GenerateHeaderFile();
void GenerateCppFile();

static string pluginName;
static string pluginDescriptorPath;
static string outputFolder;
static DescriptorsRepositorySp descriptorsRepository;
static string className;

/**
 * The entry point of the SCOTT Plugin Creator.
 */
int main(int argc, char* argv[])
{
	// Get command line inputs

	if ( argc < 2 )
	{
		cerr << "Usage: scottpc <PluginDescriptorPath> [ <OutputFolder> ] " << endl;
		exit(0);
	}

	pluginDescriptorPath = string(argv[1]);
	
	outputFolder = "./";
	if ( argc > 2 )	outputFolder = string(argv[2]);

	// Checking errors in command line inputs

	if ( !filesystem::is_regular_file(pluginDescriptorPath) )
	{
		cerr << "Error: the plugin descriptor \"" << pluginDescriptorPath << "\" not exists." << endl;
		exit(0);
	}

	string ext = filesystem::extension( pluginDescriptorPath);

	if ( ext != ".spd")
	{
		cerr << "Error: the plugin descriptor must be a file with .spd extension." << endl;
		exit(0);
	}

	if ( !filesystem::is_directory(outputFolder) )
	{
		cerr << "Error: the output folder \"" << outputFolder << "\" not exist." << endl;
		exit(0);
	}

	descriptorsRepository = DescriptorsRepository::GetInstance();

	try
	{
		cout << "Parsing type descriptor..." << endl;
		ParsePluginDescriptors();

		cout << "Generating entrypoint..." << endl;
		GenerateEntrypoint();

		cout << "Generating plugin header file..." << endl;
		GenerateHeaderFile();

		cout << "Generating plugin source file..." << endl;
		GenerateCppFile();

		cout << "Code generation completed." << endl;		
	}
	catch(string s)
	{
		cerr << s << endl;
	}

#if defined(WIN32)
	// Show the presence of memory leaks with Visual C++
	_CrtDumpMemoryLeaks();
#endif

};

string GetAttribute( TiXmlElement* elem, string attributeName )
{
	const string* pstr = elem->Attribute( attributeName );
	string str = "";

	if ( pstr )
	{
		str = string( *pstr );
	}

	trim(str);

	return str;
}

void ParsePluginDescriptors()
{
	bool ris;
	ostringstream os;

	INameResolutorSp nameResolutor = LastLoadedFirstNameResolutorSp(new LastLoadedFirstNameResolutor());
	
	// Get the plugin name from path
	pluginName = filesystem::basename(pluginDescriptorPath);
	className = pluginName + "Plugin";
	className[0] = toupper(className[0]);
	replace_all(className, "-", "");

	// Load the scott file descriptor

	TiXmlDocument doc( pluginDescriptorPath );
	ris = doc.LoadFile();
	if ( !ris )
	{
		if ( doc.ErrorId() == TiXmlBase::TIXML_ERROR_OPENING_FILE )
		{
			throw string("Error: The file descriptor " + pluginDescriptorPath + " not exists.");
		}

		os << doc.ErrorDesc() << endl;
		os << "Row: " << doc.ErrorRow() << ", Col: " << doc.ErrorCol() << endl;

		throw string( os.str() );
	}

	// Get the root element
	TiXmlHandle hDoc(&doc);
	TiXmlHandle hRoot(0);

	TiXmlElement* pluginElem = hDoc.FirstChildElement("Plugin").Element();
	if ( !pluginElem )
	{
		os << "The root tag <Plugin> not exists.";
		throw string( os.str() );
	}

	hRoot = TiXmlHandle(pluginElem);

	// Control if this plugin depends from others plugin
	TiXmlElement* dependencyElem = hRoot.FirstChild("Dependencies").FirstChild("Dependency").Element();	

	for( ; dependencyElem; dependencyElem = dependencyElem->NextSiblingElement() )
	{
		string dependentPluginName = GetAttribute( dependencyElem, "plugin");
		trim(dependentPluginName);

		// TODO: create a vector of dependent plugins
	}	

	// Build the enum types
	TiXmlElement* enumElem = hRoot.FirstChild("Types").FirstChild("Enums").FirstChild("Enum").Element();	

	for( ; enumElem; enumElem = enumElem->NextSiblingElement() )
	{
		long n = 0;
		string enumName = GetAttribute( enumElem, "name");
		string enumDescription = GetAttribute( enumElem, "description");

		try
		{
			SEnumTypeDescriptorSp etd = SEnumTypeDescriptor::Create(pluginName, enumName, enumDescription);

			// Enum entries
			TiXmlElement* entryElem = enumElem->FirstChildElement("Entry");

			for( ; entryElem; entryElem = entryElem->NextSiblingElement() )
			{
				string name = GetAttribute(entryElem, "name");
				string val = GetAttribute(entryElem, "value");
				string description = GetAttribute(entryElem, "description");

				try	
				{ 
					SNumberSp num = SNumber::Parse(val);
					n = num->Get();
				}
				catch(...)
				{
					++n;
				}

				etd->AddEntry(name, n, description);
			}

			descriptorsRepository->AddTypeDescriptor(etd);
		}
		catch(...)
		{
			os << "Syntax error in <Enum name=\"" << enumName << "\" ... >" << endl;
			throw string( os.str() );
		}
	}

	// Build the struct and the vector types
	// Note: the for loop is important if there are nested types

	for(int i=0; i<10; i++)
	{
		// Build the vector types
		TiXmlElement* vectorElem = hRoot.FirstChild("Types").FirstChild("Vectors").FirstChild("Vector").Element();	

		for( ; vectorElem; vectorElem = vectorElem->NextSiblingElement() )
		{
			string vectorName = GetAttribute( vectorElem, "name");
			string vectorItemType = GetAttribute( vectorElem, "itemType");
			string vectorDescription = GetAttribute( vectorElem, "description");

			try
			{
				try
				{
					// Item type is a simple type
					SType typeName = Utility::GetTypeFromName(vectorItemType);
					SVectorTypeDescriptorSp vtd = SVectorTypeDescriptor::Create(pluginName, vectorName, vectorDescription, typeName);

					descriptorsRepository->AddTypeDescriptor(vtd);
				}
				catch(...)
				{
					// Item type is a user defined type
					try
					{						
						TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor( nameResolutor->ResolveTypeName(vectorItemType) );
						SVectorTypeDescriptorSp vtd = SVectorTypeDescriptor::Create(pluginName, vectorName, vectorDescription, td);

						descriptorsRepository->AddTypeDescriptor(vtd);
					}
					catch(...) { }
				}
			}
			catch(...)
			{
				os << "Syntax error in <Vector name=\"" << vectorName << "\" ... >" << endl;
				throw string( os.str() );
			}

		}

		// Build the struct types

		TiXmlElement* structElem = hRoot.FirstChild("Types").FirstChild("Structs").FirstChild("Struct").Element();	

		for( ; structElem; structElem = structElem->NextSiblingElement() )
		{
			string structName = GetAttribute( structElem, "name");
			string structDescription = GetAttribute( structElem, "description");

			try
			{
				SStructTypeDescriptorSp std = SStructTypeDescriptor::Create(pluginName, structName, structDescription);

				TiXmlElement* entryElem = structElem->FirstChildElement("Member");

				for( ; entryElem; entryElem = entryElem->NextSiblingElement() )
				{
					string name = GetAttribute(entryElem, "name");
					string type = GetAttribute(entryElem, "type");
					string description = GetAttribute(entryElem, "description");

					try
					{
						// Member type is a simple type
						SType typeName = Utility::GetTypeFromName(type);

						std->AddMember(name, description, typeName);
						descriptorsRepository->AddTypeDescriptor(std);
					}
					catch(...)
					{
						// Member type is a user defined type
						try
						{
							TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor( nameResolutor->ResolveTypeName(type) );

							std->AddMember(name, description, td);
							descriptorsRepository->AddTypeDescriptor(std);
						}
						catch(...) { }
					}
				}
			}
			catch(...)
			{
				os << "Syntax error in <Struct name=\"" << structName << "\" ... >" << endl;
				throw string( os.str() );
			}
		}

	}

	// Build the commands

	TiXmlElement* commandElem = hRoot.FirstChild("Commands").FirstChild("Command").Element();

	for( ; commandElem; commandElem = commandElem->NextSiblingElement() )
	{
		TiXmlElement* descriptionElem = NULL;
		TiXmlElement* inputsElem = NULL;
		TiXmlElement* outputsElem = NULL;

		string commandName = "";
		string commandDescription = "";

		try
		{
			// Get command info
			commandName = GetAttribute(commandElem, "name");

			if ( (descriptionElem = commandElem->FirstChildElement("Description")) )
			{
				if ( descriptionElem->GetText() )
				{
					commandDescription = descriptionElem->GetText();
				}
			}

			CommandDescriptorSp cd = CommandDescriptor::Create(pluginName, commandName, commandDescription);

			// Command Inputs
			if ( (inputsElem = commandElem->FirstChildElement("Inputs")) )
			{
				TiXmlElement* parameterElem = inputsElem->FirstChildElement();

				for( ; parameterElem; parameterElem = parameterElem->NextSiblingElement() )
				{
					string name = GetAttribute(parameterElem, "name");
					string type = GetAttribute(parameterElem, "type");
					string description = GetAttribute(parameterElem, "description");

					try
					{
						// Input parameter type is a simple type
						SType typeName = Utility::GetTypeFromName(type);
						cd->AddInputParameter(name, description, typeName);
					}
					catch(...)
					{
						// Input parameter type is a user defined type
						try
						{
							TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor( nameResolutor->ResolveTypeName(type) );
							cd->AddInputParameter(name, description, td);
						}
						catch(...) { }
					}
				}
			}

			// Command Outputs

			if ( (outputsElem = commandElem->FirstChildElement("Outputs")) )
			{
				TiXmlElement* parameterElem = outputsElem->FirstChildElement();

				for( ; parameterElem; parameterElem = parameterElem->NextSiblingElement() )
				{
					string name = GetAttribute(parameterElem, "name");;
					string type = GetAttribute(parameterElem, "type");
					string description = GetAttribute(parameterElem, "description");

					try
					{
						// Output parameter type is a simple type
						SType typeName = Utility::GetTypeFromName(type);
						cd->AddOutputParameter(name, description, typeName);
					}
					catch(...)
					{
						// Output parameter type is a user defined type
						try
						{
							TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor( nameResolutor->ResolveTypeName(type) );
							cd->AddOutputParameter(name, description, td);
						}
						catch(...) { }
					}				
				}
			}

			// Add the command descriptor in the repository
			descriptorsRepository->AddCommandDescriptor(cd);
		}
		catch(...)
		{
			os << "Syntax error in <Command name=\"" << commandName << "\" ... >" << endl;
			throw string( os.str() );
		}
	}
}

/**
 * Check if a particular type is used as an output command.
 */
bool IsUsedAsOutput(TypeDescriptorSp td)
{
	string fqName = td->GetFullyQualifiedName();
	
	StringVectorSp commandNames = descriptorsRepository->GetCommandNames();
	BOOST_FOREACH(string commandName, *commandNames)
	{
		CommandDescriptorSp cd = descriptorsRepository->GetCommandDescriptor(commandName);
		
		for(int i=0; i<(int)cd->GetNumberOfOutputParameters(); ++i)
		{
			if ( fqName == cd->GetOutputParameter(i)->GetFullyQualifiedTypeName() )
			{
				return true;
			}
		}
	}

	return false;
}

void GenerateEntrypoint()
{
	string entrypointPath = outputFolder + "/entrypoint.cpp";
	ofstream stream( entrypointPath.c_str() );

	stream <<
	"#include \"" << className << ".h\"\n"
	"\n"
	"extern \"C\"\n"
	"{\n"
	"	/**\n"
	"	 *  Create the plugin instance\n"
	"	 */\n"
	"	DECLARATION_DLL Plugin* LoadPlugin()\n"
	"	{\n"
	"		return new " << className << "();\n"
	"	}\n"
	"};\n";

	stream.close();
}

void GenerateHeaderFile()
{
	string headerPath = outputFolder + "/" + className + ".h";

	ofstream stream( headerPath.c_str() );

	stream <<
	"#if !defined(_" << className << "_H)\n"
	"#define _" << className << "_H\n"
	"\n"
	"#include <scott/Plugin.h>\n"
	"#include <winscard.h>\n"
	"#include <iostream>\n"
	"\n"
	"CREATE_ALIAS( " << className << " );\n"
	"\n"
	"class DECLARATION_DLL " << className << " :	public Plugin\n"
	"{\n"
	"	// Useful file descriptors references\n";

	// Creating file descriptors reference
	StringVectorSp typeNames = descriptorsRepository->GetTypeNames();
	BOOST_FOREACH(string typeName, *typeNames)
	{
		TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor(typeName);
		if ( td->Describe( STypeEnum ))			stream << "	SEnumTypeDescriptorSp	";
		else if ( td->Describe( STypeVector))	stream << "	SVectorTypeDescriptorSp	";
		else if ( td->Describe(STypeStruct))	stream << "	SStructTypeDescriptorSp	";

		stream << td->GetName() << "Td;" << endl;
	}

	stream << 
	"\n"
	"	// Enumerators default values\n";
	
	// Creating enumerator defalut values declaration
	typeNames = descriptorsRepository->GetTypeNames();
	BOOST_FOREACH(string typeName, *typeNames)
	{
		TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor(typeName);
		if ( td->Describe( STypeEnum ) && IsUsedAsOutput(td) )			
		{
			stream << "	string " << td->GetName() << "Default;" << endl;
		}
	}

	stream <<
	"\n"
	"public:\n"
	"\n"
	"	" << className << "();\n"
	"\n"
	"	virtual void InitializePlugin(PluginSpMapSp plugins, INameResolutorSp nameResolutor);\n"
	"\n"
	"	virtual void ExecuteCommand(CommandSp command);\n"
	"\n"
	"	// Plugin Command Handler Declarations\n";

	// Creating command handlers declarations
	StringVectorSp commandNames = descriptorsRepository->GetCommandNames();
	BOOST_FOREACH(string commandName, *commandNames)
	{
		CommandDescriptorSp cd = descriptorsRepository->GetCommandDescriptor(commandName);

		string methodName = pluginName + "_" + cd->GetName();
		methodName[0] = toupper(methodName[0]);

		stream << "	virtual void " <<  methodName << "();" << endl;
	}

	stream <<
	"\n"
	"	// Methods to set enumerators\n";

	// Creating methods to set enumerators
	typeNames = descriptorsRepository->GetTypeNames();
	BOOST_FOREACH(string typeName, *typeNames)
	{
		TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor(typeName);
		if ( td->Describe( STypeEnum ) && IsUsedAsOutput(td) )			
		{
			stream << "	virtual void Set" << td->GetName() << "(string outputParameterName, string enumValue);" << endl;
			stream << "	virtual void Set" << td->GetName() << "(string outputParameterName, unsigned long enumNumericValue);" << endl;
		}
	}
	
	stream <<
	"};\n"
	"\n"
	"#endif  // _" << className << "_H\n"
	"\n";

	stream.close();
}

void GenerateCppFile()
{
	string cppFilePath = outputFolder + "/" + className + ".cpp";

	ofstream stream( cppFilePath.c_str() );

	stream <<
	"#include \"" << className << ".h\"\n"
	"\n"
	"\n"
	"" << className << "::" << className << "() : Plugin(\"" << pluginName << "\")\n"
	"{\n";

	stream <<
	"	// Set the default enumerator values\n";

	StringVectorSp typeNames = descriptorsRepository->GetTypeNames();
	BOOST_FOREACH(string typeName, *typeNames)
	{
		TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor(typeName);
		if ( td->Describe( STypeEnum ) && IsUsedAsOutput(td) )
		{
			SEnumTypeDescriptorSp etd = td->As<SEnumTypeDescriptor>();
			string firstEntry = etd->GetEntry(0)->GetValue();

			stream << "	" << etd->GetName() << "Default = \"" << firstEntry << "\";" << endl;
		}
	}

	stream <<
	"}\n"
	"\n"
	"void " << className << "::InitializePlugin( PluginSpMapSp plugins, INameResolutorSp nameResolutor )\n"
	"{\n"
	"	Plugin::InitializePlugin(plugins, nameResolutor);\n"
	"\n"
	"	// Get useful references to type descriptors\n";

	// Creating file descriptors reference
	typeNames = descriptorsRepository->GetTypeNames();
	BOOST_FOREACH(string typeName, *typeNames)
	{
		TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor(typeName);
		stream << "	" << td->GetName() << "Td = descriptorsRepository->";

		if ( td->Describe( STypeEnum ))			stream << "GetEnumTypeDescriptor(";
		else if ( td->Describe( STypeVector))	stream << "GetVectorTypeDescriptor(";
		else if ( td->Describe(STypeStruct))	stream << "GetStructTypeDescriptor(";

		stream << "\"" << td->GetFullyQualifiedName() << "\");" << endl;
	}

	stream <<
	"}\n"
	"\n"
	"void " << className << "::ExecuteCommand(CommandSp cmd)\n"
	"{\n"
	"	Plugin::ExecuteCommand(cmd);\n"
	"\n"
	"	// Call the right command handler\n";

	StringVectorSp commandNames = descriptorsRepository->GetCommandNames();
	for(int i=0; i<(int)commandNames->size(); ++i)
	{
		CommandDescriptorSp cd = descriptorsRepository->GetCommandDescriptor( (*commandNames)[i] );

		string commandName = cd->GetName();
		string methodName = pluginName + "_" + cd->GetName();
		methodName[0] = toupper(methodName[0]);

		if ( i == 0)
		{
			stream << "	if ( commandName == \"" << commandName << "\" )	";
			stream << methodName << "();\n";
		}
		else
		{
			stream << "	else if ( commandName == \"" << commandName << "\" )	";
			stream << methodName << "();\n";
		}
	}
	if (commandNames->size() > 0)
	{
		stream << "	else throw SPluginException(\"Error: command not implemented by plugin.\");\n";
	}

	stream << 
	"\n"
	"}\n"
	"\n";

	/*************************************************/
	/*  Creating the command handler implementation  */
	/*************************************************/

	commandNames = descriptorsRepository->GetCommandNames();
	BOOST_FOREACH(string commandNameFQ, *commandNames)
	{
		CommandDescriptorSp cd = descriptorsRepository->GetCommandDescriptor( commandNameFQ );

		string commandName = cd->GetName();
		string methodName = pluginName + "_" + cd->GetName();
		methodName[0] = toupper(methodName[0]);

		stream <<
		"void " << className << "::" << methodName << "()\n"
		"{\n"
		"	// Input preparation   \n";

		// Generating input code

		for(int i=0; i< (int) cd->GetNumberOfInputParameters(); ++i)
		{
			InputParameterSp ip = cd->GetInputParameter(i);
			SType ipType = ip->GetType();

			stream << "	";

			if ( Utility::IsSimpleType(ipType) )
			{
				stream << Utility::GetTypeName(ipType) << "Sp ";
			}
			else
			{
				if ( ipType == STypeEnum )	 stream << "SEnumSp ";
				if ( ipType == STypeVector ) stream << "SVectorSp ";
				if ( ipType == STypeStruct ) stream << "SStructSp ";
			}

			stream << ip->GetName() << "  = inputs->Get";

			if ( Utility::IsSimpleType(ipType) )
			{
				stream << "<" << Utility::GetTypeName(ipType) << ">";
			}
			else
			{
				if ( ipType == STypeEnum )   stream << "<SEnum>";
				if ( ipType == STypeVector ) stream << "<SVector>";
				if ( ipType == STypeStruct ) stream << "<SStruct>";
			}

			stream << "(\"" << ip->GetName() << "\");" << endl;
		}

		stream <<
		"\n"
		"	// Insert plugin operations here\n"
		"\n"
		"	// Setting outputs";

		// Generating output code
		for(int i=0; i< (int) cd->GetNumberOfOutputParameters(); ++i)
		{
			OutputParameterSp op = cd->GetOutputParameter(i);
			SType opType = op->GetType();

			stream << "\n	";

			if ( Utility::IsSimpleType(opType) )
			{
				// Set simple type output variables
				stream << "outputs->Set(\"" << op->GetName() << "\", ";
				stream << Utility::GetTypeName(opType) << "::Create(";

				if ( opType == STypeByte) stream << "0";
				if ( opType == STypeNumber) stream << "0";
				if ( opType == STypeChar) stream << "'?'";
				if ( opType == STypeString) stream << "\"???\"";

				stream << ") );\n";
			}
			else
			{
				TypeDescriptorSp td = op->GetTypeDescriptor();
				string tdName = td->GetName() + "Td";

				if ( opType == STypeEnum )	
				{
					// Set enum type output variable
					//stream << "SetEnumOutput( " << tdName << ", \"" << op->GetName() << "\", 0, \"Put here default enum value\"); ";

					SEnumTypeDescriptorSp etd = td->As<SEnumTypeDescriptor>();
					string firstEntry = etd->GetEntry(0)->GetValue();

					stream << "Set" << td->GetName() << "(\"" << op->GetName() << "\", \"" << firstEntry << "\");"; 
				}
				else if ( opType == STypeVector )
				{
					// Set vector type output variable
					stream << "SVectorSp " << op->GetName() << " = SVector::Create( " << tdName << ");" << endl;
					stream << "	outputs->Set(\"" << op->GetName() << "\", " << op->GetName() << ");";
				}
				else if ( opType == STypeStruct )
				{
					// Set struct type output variable
					stream << "SStructSp " << op->GetName() << " = SStruct::Create( " << tdName << ");" << endl;
					stream << "	outputs->Set(\"" << op->GetName() << "\", " << op->GetName() << ");";
				}
			}
		}		

		stream <<
			"\n}\n"	
			"\n";
	}

	stream <<
	"\n"
	"/*****************************************************/\n"	
	"/*           Enumerator support methods              */\n"	
	"/*****************************************************/\n"	
	"\n";

	typeNames = descriptorsRepository->GetTypeNames();
	BOOST_FOREACH(string typeName, *typeNames)
	{
		TypeDescriptorSp td = descriptorsRepository->GetTypeDescriptor(typeName);

		if ( td->Describe( STypeEnum ) )	
		{
			stream <<
			"void " << className << "::Set" << td->GetName() << "( string outputParameterName, string enumValue )\n"
			"{\n"
			"	if ( " << td->GetName() << "Td->IsDefined(enumValue) )\n"
			"	{\n"
			"		outputs->Set(outputParameterName, SEnum::Create(" << td->GetName() << "Td, enumValue) );\n"
			"	}\n"
			"	else\n"
			"	{\n"
			"		outputs->Set(outputParameterName, SEnum::Create(" << td->GetName() << "Td, " << td->GetName() << "Default) );\n"
			"	}\n"
			"}\n";

			stream <<
			"void " << className << "::Set" << td->GetName() << "( string outputParameterName, unsigned long enumNumericValue )\n"
			"{\n"
			"	string enumValue = " << td->GetName() << "Default;\n"
			"\n";
			
			SEnumTypeDescriptorSp etd = td->As<SEnumTypeDescriptor>();

			for(int i=0; i<(int)etd->GetNumberOfEntries(); ++i)
			{
				string enumName = etd->GetEntry(i)->GetValue();

				stream <<
				"	if ( enumNumericValue == " << enumName << " )	enumValue = \"" << enumName << "\";\n";
			}

			stream <<
			"\n"
			"	outputs->Set(outputParameterName, SEnum::Create(" << td->GetName() << "Td, enumValue) );\n"
			"}\n";
		}
	}

	stream.close();
}
